import urllib.parse
import urllib.request
import urllib.error
import http.cookiejar
import ssl

import os
import json
import gzip
import uuid

import time, timeit
import random
from datetime import datetime
from datetime import timedelta

import snowflake.client

from concurrent import futures


import db_handler


headers = [
    ("Accept", "*/*"),
    ("Accept-Encoding", "gzip, deflate, br"),
    ("Accept-Language", "zh-CN,zh;q=0.9"),
    ("User-Agent",
     "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"),
]
opener = urllib.request.build_opener()
opener.addheaders = headers

root_url = "http://localhost:3000/playlist/detail"

song_root_url = "http://localhost:3000/song/detail"

song_url_root_url = "http://localhost:3000/music/url"

lyric_root_url = "http://localhost:3000/lyric"

local_song_path = "D:/yunmusic_dev/song"

local_lyric_path = "D:/yunmusic_dev/lyric"


def get_playlist_has_song(playlist_id):
    playlist_detail_url = root_url + "?id=" + str(playlist_id)

    print("get songs from", playlist_detail_url)
    try:
        resp = opener.open(playlist_detail_url)
    except Exception as e:
        print(e)
        print("ignore error")
        return False

    if resp.info().get('Content-Encoding') == 'gzip':
        resp_decode = gzip.decompress(resp.read()).decode("utf-8")
    else:
        resp_decode = resp.read().decode("utf-8")
    resp_json = json.loads(resp_decode)

    print(resp_json)

    tracks = resp_json['playlist']['tracks']

    for song in tracks:
        song_id = song["id"]
        name = song['name']

        if db_handler.exist_playlist_has_song(playlist_id, song_id):
            continue

        if not db_handler.exist(song_id, db_handler.Song):
            continue

        id = str(snowflake.client.get_guid())

        db_handler.add(db_handler.PlaylistHasSong(id=id,
                                                  song_id=song_id,
                                                  playlist_id=playlist_id))

        print("add", name, "ok")
        # 随机暂停一段时间
        seconds = random.randint(1, 5)
        time.sleep(seconds)


def get_song_ids_by_playlist_id(playlist_id):
    playlist_detail_url = root_url + "?id=" + str(playlist_id)

    print("get songs from", playlist_detail_url)
    try:
        resp = opener.open(playlist_detail_url)
    except Exception as e:
        print(e)
        print("ignore error")
        return False

    if resp.info().get('Content-Encoding') == 'gzip':
        resp_decode = gzip.decompress(resp.read()).decode("utf-8")
    else:
        resp_decode = resp.read().decode("utf-8")
    resp_json = json.loads(resp_decode)

    print(resp_json)

    tracks = resp_json['playlist']['tracks']

    for song in tracks:
        song_id = song["id"]
        name = song['name']
        publish_time = song['publishTime']

        if db_handler.exist(song_id, db_handler.Song):
            continue

        song_url = get_song_url_by_id(song_id)
        song_url_id = song_id

        lyric = get_lyric_by_id(song_id)

        download_song(song_url, str(song_url_id) + ".mp3")

        db_handler.add(db_handler.Song(id=song_id,
                                       name=name,
                                       song_url_id=song_url_id,
                                       publish_time=get_datetime_from_seconds(publish_time),
                                       lyric=lyric))
        print("add", name, "ok")
        # 随机暂停一段时间
        seconds = random.randint(1, 5)
        time.sleep(seconds)


def get_datetime_from_seconds(seconds):
    time_array = time.localtime(float(seconds)/1000)  # 1970秒数
    # print(time_array)
    otherStyleTime = time.strftime("%Y-%m-%d %H:%M:%S", time_array)
    datetime1 = datetime.strptime(otherStyleTime, "%Y-%m-%d %H:%M:%S")
    return datetime1


def download_lyric(lyric, lyric_name):
    fh = open(os.path.join(local_lyric_path, lyric_name), 'w')
    fh.write(lyric)
    fh.close()


def download_song(song_url, song_name):

    if not os.path.exists(local_song_path):
        os.makedirs(local_song_path)

    try:
        urllib.request.urlretrieve(song_url, os.path.join(local_song_path, song_name))
    except Exception as e:
        raise e
    print("download", song_name, "ok")


def get_song_url_by_id(song_id):
    song_url_url = song_url_root_url + "?id=" + str(song_id) + "&br=1280000"

    print("get song_url from", song_url_url)
    try:
        resp = opener.open(song_url_url)
    except Exception as e:
        print(e)
        print("ignore error")
        return False

    if resp.info().get('Content-Encoding') == 'gzip':
        resp_decode = gzip.decompress(resp.read()).decode("utf-8")
    else:
        resp_decode = resp.read().decode("utf-8")
    resp_json = json.loads(resp_decode)

    print(resp_json)

    song_url = resp_json['data'][0]['url']

    return song_url


def get_lyric_by_id(song_id):
    lyric_url = lyric_root_url + "?id=" + str(song_id)

    print("get lyric from", lyric_url)
    try:
        resp = opener.open(lyric_url)
    except Exception as e:
        print(e)
        print("ignore error")
        return False

    if resp.info().get('Content-Encoding') == 'gzip':
        resp_decode = gzip.decompress(resp.read()).decode("utf-8")
    else:
        resp_decode = resp.read().decode("utf-8")
    resp_json = json.loads(resp_decode)

    print(resp_json)

    lyric = resp_json['lrc']['lyric']

    return lyric


def get_playlist_ids_from_db():
    playlists = db_handler.query_all(db_handler.Playlist)
    ids = [playlist.id for playlist in playlists]
    return ids


def get_songs_from_playlist_ids(ids):
    workers = min(len(ids), 20)
    with futures.ThreadPoolExecutor(workers) as executor:
        executor.map(get_playlist_has_song, ids)
        # executor.map(get_song_ids_by_playlist_id, ids)


if __name__ == '__main__':
    ids = get_playlist_ids_from_db()
    get_songs_from_playlist_ids(ids)

